/*
 * CSocket.cpp
 *
 *  Created on: 6 oct. 2009
 *      Author: Maxime Gaudin
 */

#include "CSocket.h"

// Constructeurs & Destructeurs ================================================================================
CSocket::CSocket(std::string ServerAddr, int ServerPort)
{
	serverAddr = ServerAddr;
	serverPort = ServerPort;

	socketID = createSocket();
}

// Getter ======================================================================================================
SocketState CSocket::getState()	{return state;}

// Méthodes publiques ==========================================================================================
int CSocket::Connect()
{
	return Connect(serverAddr, serverPort);
}

int CSocket::Connect(std::string ServerAddr, int ServerPort)
{
	struct sockaddr_in RemoteServer;

	#ifdef DEBUG
		std::cout << "Connection to " << ServerAddr << ":" << ServerPort << " ..." << std::endl;
	#endif

	if(ResolveHostByName(ServerAddr) == NULL ) state = NONE;

	if(state != NONE)
	{
		state = CONNECTING;

		#ifdef DEBUG
			std::cout << "Data Structure initialization ... (" << ResolveHostByName(ServerAddr) << "::" << ServerPort << " )" << std::endl;
		#endif

		memset(&RemoteServer, 0, sizeof(RemoteServer));					// Vidage de la structure
		RemoteServer.sin_family = AF_INET;								// Protocole IP
		RemoteServer.sin_addr.s_addr = inet_addr(ResolveHostByName(ServerAddr));
		RemoteServer.sin_port = htons(ServerPort);

		if (connect(socketID, (struct sockaddr *) &RemoteServer, sizeof(RemoteServer)) == -1)
		{
				state = ERR_CONNECTING;

				#ifdef DEBUG
					std::cout << "Error : Can't connect to server  !" << std::endl;
				#endif

				return -1;
		}

		#ifdef DEBUG
			std::cout << "Connected  !" << std::endl;
		#endif

		state = CONNECTED;
		return 0;
	}
	else
	{
		#ifdef DEBUG
			std::cout << "Socket not created  (Hostname Reachable ?), can't connect !" << std::endl;
		#endif

		return -1;
	}
}

void CSocket::Disconnect()
{
	#ifdef DEBUG
		std::cout << "Disconnecting..." << std::endl;
	#endif

	close(socketID);
	state = CLOSED;

	#ifdef DEBUG
		std::cout << "Disconnected !" << std::endl;
	#endif
}

int CSocket::Send(std::string Data)
{
	return Send((char*)Data.c_str(), Data.size());
}

int CSocket::Send(char* Data, unsigned int Size)
{
	#ifdef DEBUG
		std::cout << "Sending :" << Data << std::endl;
	#endif

	if(state != NONE)
	{
		state = SENDING;

		if(send(socketID, Data, Size, 0) != static_cast<int>(Size))
		{
			#ifdef DEBUG
				std::cout << "Error : Can't send data to server  !" << std::endl;
			#endif

			state = ERR_SENDING;
			return -1;
		}

		#ifdef DEBUG
			std::cout << "Sent (" << Size << " bytes) !" << std::endl;
		#endif
		state = CONNECTED;

		return 0;
	}
	else
	{
		#ifdef DEBUG
			std::cout << "Socket not created  (Hostname Reachable ?), can't send data !" << std::endl;
		#endif

		return -1;
	}
}

char* CSocket::Receive()
{
	return Receive(BUFFSIZE);
}

char* CSocket::Receive(int BufferSize)
{
	#ifdef DEBUG
		std::cout << "Receiving..." << std::endl;
	#endif

	if(state != NONE)
	{
		char* Buffer = new char[BufferSize];

		state = RECEIVING;

		int bytesReceived = recv(socketID, Buffer, BufferSize - 2, MSG_WAITALL);

		if(bytesReceived < 0)
		{
			#ifdef DEBUG
				std::cout << "Error : Can't receive data !" << std::endl;
			#endif

			state = ERR_RECEIVING;
			return NULL;
		}

		Buffer[BufferSize - 1] = '\0';

		#ifdef DEBUG
			std::cout << "Bytes received : " << bytesReceived << std::endl;
			std::cout << "Data received : " << Buffer << std::endl;
		#endif

		return Buffer;
	}
	else
	{
		#ifdef DEBUG
			std::cout << "Socket not created  (Hostname Reachable ?), can't receive data !" << std::endl;
		#endif

		return NULL;
	}
}

char* CSocket::ResolveHostByName(std::string HostName)
{
	struct in_addr ServerAddress;
	struct hostent* Host = gethostbyname(HostName.c_str());

	if(Host == NULL)
	{
		#ifdef DEBUG
			std::cout << "Host unreachable !" << std::endl;
		#endif

		return NULL;
	}

	memcpy(&ServerAddress.s_addr, Host->h_addr_list[0], sizeof(ServerAddress.s_addr));
	return inet_ntoa(ServerAddress);
}

// Méthodes privées ============================================================================================
int CSocket::createSocket()
{
	#ifdef DEBUG
		std::cout << "Socket initialization..." << std::endl;
	#endif

	int sktID = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);	// PF_INET = TCP/IP

	if (sktID < 0)
	{
		#ifdef DEBUG
			std::cout << "Can't create socket !" << std::endl;
		#endif

		state = NONE;

		return -1;
	}

	#ifdef DEBUG
		std::cout << "Socket created (" << sktID << ")" << std::endl;
	#endif

	state = IDLE;
	return sktID;
}









